package com.tanhua.server.service;

import cn.hutool.core.collection.CollectionUtil;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.constant.Constants;
import com.tanhua.commons.exception.TanHuaException;
import com.tanhua.dubbo.api.db.UserInfoApi;
import com.tanhua.dubbo.api.mongo.CommentApi;
import com.tanhua.dubbo.api.mongo.MovementApi;
import com.tanhua.dubbo.api.mongo.VisitorApi;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VisitorsVo;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.tomcat.util.bcel.Const;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class MovementService {

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private MovementApi movementApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private CommentApi commentApi;

    @DubboReference
    private VisitorApi visitorApi;

    /**
     * 发布动态
     *
     * @param imageContent 上传的图片数组
     * @param paramMap     其它参数
     */
    public void post(MultipartFile[] imageContent, Map<String, String> paramMap) {
        //1. 文本内容不能为空
        String textContent = paramMap.get("textContent");
        if (StringUtils.isEmpty(textContent)) {
            throw new TanHuaException("动态文本内容不能为空!");
        }
        //2. 把图片上传到oss上
        List<String> medias = new ArrayList<>();
        if (null != imageContent) {
            try {
                for (MultipartFile pic : imageContent) {
                    // 上传
                    String picUrl = ossTemplate.upload(pic.getOriginalFilename(), pic.getInputStream());
                    medias.add(picUrl);
                }
            } catch (IOException e) {
                throw new TanHuaException("上传图片失败!");
            }
        }
        //3. 构建pojo
        Movement pojo = new Movement();
        pojo.setUserId(UserHolder.getUserId());
        pojo.setMedias(medias);
        pojo.setTextContent(textContent);
        pojo.setLocationName(paramMap.get("location"));
        pojo.setLongitude(paramMap.get("longitude"));
        pojo.setLatitude(paramMap.get("latitude"));
        //4. 调用api发布动态
        movementApi.add(pojo);
    }

    /**
     * 查看个人动态
     * @param page
     * @param pageSize
     * @param userId
     * @return
     */
    public PageResult<MovementsVo> findPageByUserId(Long page, Long pageSize, Long userId) {
        //0. 判断userId是否为空，是则使用登录用户id
        Long searchUserId = UserHolder.getUserId();
        if(null != userId){
            searchUserId = userId;
        }
        //1. 通过用户id分页查询动态列表 pageResult
        List<MovementsVo> voList = new ArrayList<>();
        PageResult pageResult = movementApi.findPageByUserId(page,pageSize, searchUserId);
        List<Movement> movementList = pageResult.getItems();
        if(CollectionUtil.isNotEmpty(movementList)) {
            //2. 查询作者信息
            UserInfo userInfo = userInfoApi.findById(searchUserId);
            //3. 把动态与用户信息转成vo
            voList = movementList.stream().map(m->MovementsVo.init(userInfo, m)).collect(Collectors.toList());
        }
        //4. 设置回pageResult
        pageResult.setItems(voList);
        //5. 返回
        return pageResult;
    }

    /**
     * 朋友圈，查询朋友们发布的动态
     * @param page
     * @param pageSize
     * @return
     */
    public PageResult<MovementsVo> findFriendMovements(Long page, Long pageSize) {
        //1. 通过登录用户id分页查询朋友们发布的动态
        PageResult pageResult = movementApi.findFriendMovements(page, pageSize, UserHolder.getUserId());
        List<Movement> movementList = pageResult.getItems();
        List<MovementsVo> voList = convert2Vo(movementList);
        //5. 设置回pageResult
        pageResult.setItems(voList);
        //6. 返回
        return pageResult;
    }

    /**
     * 推荐动态
     * @param page
     * @param pageSize
     * @return
     */
    public PageResult<MovementsVo> recommend(Long page, Long pageSize) {
        //1. 先从redis中取
        //1.1 key
        String key = "MOVEMENTS_RECOMMEND_" + UserHolder.getUserId();
        //1.2 redis查询
        String pidsString = stringRedisTemplate.opsForValue().get(key);
        List<Movement> movementList = new ArrayList<>();
        long total = 10;
        if(StringUtils.isNotEmpty(pidsString)){
            // pidsString "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20"
            String[] pidArr = StringUtils.split(pidsString,",");
            total = pidArr.length;
            // 开始
            long start = (page-1) * pageSize;
            // 通过推荐pid查询动态
            if(total > start){
                // 分页处理,获取需要查询的动态的pid
                List<Long> pids = Arrays.stream(pidArr).skip(start).map(Long::valueOf).limit(pageSize).collect(Collectors.toList());
                // 通过pid查询动态信息
                movementList = movementApi.findPids(pids);
            }
        }else {
            //2. redis没有，则数据库随机给10条
            movementList = movementApi.randomMovement();
            total = movementList.size();
        }
        //5. 转成vo, 设置回pageResult
        List<MovementsVo> voList = convert2Vo(movementList);
        //6. 返回
        return new PageResult<MovementsVo>(page,pageSize,total,voList);
    }

    /*public static void main(String[] args) {
        long page = 2;
        long pageSize = 5;

        List<String> result = Arrays.stream("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20".split(","))
                .skip((page - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
        result.forEach(System.out::println);
    }*/

    private List<MovementsVo> convert2Vo(List<Movement> movementList){
        List<MovementsVo> voList = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(movementList)) {
            //2. 取出朋友们的id
            List<Long> userIds = movementList.stream().map(Movement::getUserId).collect(Collectors.toList());
            //3. 批量查询朋友们的信息
            Map<Long, UserInfo> userInfoMap = userInfoApi.findByBatchIds(userIds, null);
            //4. 转成vo
            for (Movement m : movementList) {
                // 取出作者（朋友）id
                MovementsVo vo = MovementsVo.init(userInfoMap.get(m.getUserId()), m);
                // 是否点赞
                String redisKey = Constants.MOVEMENTS_INTERACT_KEY + m.getId().toHexString();
                String hashMapKey= Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
                if (stringRedisTemplate.opsForHash().hasKey(redisKey, hashMapKey)) {
                    // 存在这个key, 说明登录用户对这个动态点赞过了
                    vo.setHasLiked(1);
                }
                // 是否喜欢
                String hashMapLoveKey= Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
                if (stringRedisTemplate.opsForHash().hasKey(redisKey, hashMapLoveKey)) {
                    // 存在这个key, 说明登录用户对这个动态喜欢过了
                    vo.setHasLoved(1);
                }
                voList.add(vo);
            }
        }
        return voList;
    }

    /**
     * 查询单条动态
     * @param movementId
     * @return
     */
    public MovementsVo findById(String movementId) {
        //1. 通过动态id查询动态信息
        Movement movement = movementApi.findById(movementId);
        //2. 获取动态作者
        Long userId = movement.getUserId();
        //3. 通过作者id，查询作者信息
        UserInfo userInfo = userInfoApi.findById(userId);
        //4. 转成vo
        MovementsVo vo = MovementsVo.init(userInfo, movement);
        //5. 返回
        return vo;
    }

    /**
     * 点赞
     * @param movementId
     * @return
     */
    public Integer like(String movementId) {
        // 构建pojo
        Comment pojo = new Comment();
        // 设置属性
        pojo.setPublishId(new ObjectId(movementId));
        pojo.setCommentType(CommentType.LIKE.getType());
        pojo.setUserId(UserHolder.getUserId());

        // 调用api添加点赞
        Integer likeCount = commentApi.add(pojo);

        //TODO 添加标记当前登录用户点赞了这个动态, 动态展示时，如果当前点赞过，则赞的标记高亮
        // 节省空间，容易管理
        // 标记使用hashMap, redisKey=动态的id, hashMap<like_userId, 1>
        //                                   hashMap<love_userId, 1>
        // p1: redis中的key, p2: HashMap中的key, p3: 值：随意
        String redisKey = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashMapKey= Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        stringRedisTemplate.opsForHash().put(redisKey, hashMapKey, "1");
        return likeCount;
    }

    /**
     * 动态取消点赞
     * @param movementId
     * @return
     */
    public Integer dislike(String movementId) {
        //1. 构建pojo
        Comment pojo = new Comment();
        //2. 设置要删除的条件
        pojo.setPublishId(new ObjectId(movementId));
        pojo.setCommentType(CommentType.LIKE.getType());
        pojo.setUserId(UserHolder.getUserId());
        //3. 调用api删除
        Integer likeCount = commentApi.remove(pojo);
        //4. 删除redis中的点赞标记
        String redisKey = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashMapKey= Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        stringRedisTemplate.opsForHash().delete(redisKey,hashMapKey);
        //5. 返回最新数量
        return likeCount;
    }

    /**
     * 喜欢
     * @param movementId
     * @return
     */
    public Integer love(String movementId) {
        // 构建pojo
        Comment pojo = new Comment();
        // 设置属性
        pojo.setPublishId(new ObjectId(movementId));
        pojo.setCommentType(CommentType.LOVE.getType());
        pojo.setUserId(UserHolder.getUserId());

        // 调用api添加喜欢
        Integer loveCount = commentApi.add(pojo);
        String redisKey = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashMapKey= Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
        stringRedisTemplate.opsForHash().put(redisKey, hashMapKey, "1");
        return loveCount;
    }

    /**
     * 动态取消喜欢
     * @param movementId
     * @return
     */
    public Integer unlove(String movementId) {
        //1. 构建pojo
        Comment pojo = new Comment();
        //2. 设置要删除的条件
        pojo.setPublishId(new ObjectId(movementId));
        pojo.setCommentType(CommentType.LOVE.getType());
        pojo.setUserId(UserHolder.getUserId());
        //3. 调用api删除
        Integer loveCount = commentApi.remove(pojo);
        //4. 删除redis中的喜欢标记
        String redisKey = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashMapKey= Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
        stringRedisTemplate.opsForHash().delete(redisKey,hashMapKey);
        //5. 返回最新数量
        return loveCount;
    }

    /**
     * 首页中的 最近访客
     * @return
     */
    public List<VisitorsVo> findLast4Visitors() {
        //1. 通过redis查询是否存在最后一次查询访客列表时间
        // hashMap redisKey 固定. HashMap<用户id,最近的时间>
        String redisKey = Constants.VISITORS_USER;
        String whoKey = UserHolder.getUserId().toString();
        String lastTime = (String) stringRedisTemplate.opsForHash().get(redisKey, whoKey);
        //2. 调用api查询访客表，取最近4条记录
        List<Visitors> visitorList = visitorApi.findLast4Visitors(UserHolder.getUserId(), lastTime);
        //3. 取出访客的ids
        List<VisitorsVo> voList = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(visitorList)) {
            List<Long> visitorIds = visitorList.stream().map(Visitors::getVisitorUserId).collect(Collectors.toList());
            //4. 批量查询访客信息
            List<UserInfo> visitorsInfoList = userInfoApi.findByBatchIds(visitorIds);
            //5. 转成vo
            voList = visitorsInfoList.stream().map(v -> VisitorsVo.init(v)).collect(Collectors.toList());
        }
        //6. 返回
        return voList;
    }
}
